package org.example.spring.simple.framework.webmvc.servlet;

import org.example.spring.simple.framework.annotation.ZRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * HandlerAdapter主要完成请求传递到服务端的参数列表与Method实参列表的对应关系，
 * 完成参数值的类型转换工作。核心方法 是handle()，
 * 在handle()方法中用反射来调用被适配的目标方法，并将转换包装好的参数列表传递过去。
 */
public class ZHandlerAdapter {
    public boolean supports(Object handler) {
        return (handler instanceof ZHandlerMapping);
    }

    public ZModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        ZHandlerMapping handlerMapping = (ZHandlerMapping)handler;
        //把方法的形参列表和request的参数列表所在顺序进行一一对应
        Map<String, Integer> paramIndexMapping = new HashMap<>();
        //提取方法中加了注解的参数
        Annotation[][] annotations = handlerMapping.getMethod().getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            for (Annotation annotation : annotations[i]) {
                if (annotation instanceof ZRequestParam) {
                    String paramName = ((ZRequestParam) annotation).value();
                    if (!"".equals(paramName.trim())) {
                        paramIndexMapping.put(paramName, i);
                    }
                }
            }
        }
        //提取方法中的request和response参数
        Class<?> [] paramsTypes = handlerMapping.getMethod().getParameterTypes();
        for (int i = 0; i < paramsTypes.length ; i ++) {
            Class<?> type = paramsTypes[i];
            if(type == HttpServletRequest.class ||
                    type == HttpServletResponse.class){
                paramIndexMapping.put(type.getName(),i);
            }
        }
        //获得方法的形参列表
        Map<String,String[]> params = request.getParameterMap();
        //创建实参列表
        Object[] paramValues = new Object[paramsTypes.length];
        for (Map.Entry<String, String[]> param : params.entrySet()) {
            String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]","")
                    .replaceAll("\\s",",");
            if (!paramIndexMapping.containsKey(param.getKey())){
                continue;
            }
            int index = paramIndexMapping.get(param.getKey());
            paramValues[index] = castStringValue(value, paramsTypes);
        }

        if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
            int reqIndex = paramIndexMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex] = request;
        }

        if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
            int respIndex = paramIndexMapping.get(HttpServletResponse.class.getName());
            paramValues[respIndex] = response;
        }

        //handler中取出controller和method，通过反射进行调用
        Object result = handlerMapping.getMethod().invoke(handlerMapping.getController(), paramValues);
        if (result == null || result instanceof Void) {
            return null;
        }
        boolean isModelAndView = handlerMapping.getMethod().getReturnType() == ZModelAndView.class;
        if (isModelAndView) {
            return (ZModelAndView) result;
        } else {
            return null;
        }
    }

    private Object castStringValue(String value, Class<?>[] paramsType) {
        if(String.class.equals(paramsType)){
            return value;
        }
        //如果是int
        if(Integer.class.equals(paramsType)){
            return Integer.valueOf(value);
        }
        else if(Double.class.equals(paramsType)){
            return Double.valueOf(value);
        }else {
            if(value != null){
                return value;
            }
            return null;
        }
    }
}
